package com.zheng.redpacket.server.serivce.Impl;

import com.sun.xml.internal.bind.v2.TODO;
import com.zheng.redpacket.mdg.mapper.UserMapper;
import com.zheng.redpacket.mdg.model.User;
import com.zheng.redpacket.server.dto.UserRegDto;
import com.zheng.redpacket.server.serivce.RedisService;
import com.zheng.redpacket.server.serivce.UserRegService;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.tomcat.jni.Lock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class UserRegServiceImpl implements UserRegService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserRegService.class);
    private static final String PATH = "/user/zkLock";

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CuratorFramework client;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void userReg(UserRegDto dto) throws Exception {
        final String key = dto.getUserName()+"-lock";
        final String value = System.nanoTime() + "" +UUID.randomUUID();
        Boolean res = redisService.setIfAbsent(key, value);
        LOGGER.info((String) redisService.get(key));
        if (res != null) {
            redisService.expire(key, 20L);
            try {
                User user = userMapper.selectByUserName(dto.getUserName());
                if (user == null) {
                    LOGGER.info("lock：{}",dto.getUserName());
                    User reg = new User();
                    BeanUtils.copyProperties(dto, reg);
                    reg.setCreateTime(new Date());
                    userMapper.insertSelective(reg);
                }else {
                    throw new Exception("用户已被注册");
                }
            } catch (Exception e) {
                throw e;
            }finally {
                if (value.equals(redisService.get(key).toString())) {
                    redisService.del(key);
                }
            }
        }
    }

    @Override
    public void userRegLockByZkLock(UserRegDto dto) throws Exception {
        InterProcessMutex mutex = new InterProcessMutex(client, PATH + dto.getUserName() + "-lock");
        try {
            if (mutex.acquire(10L, TimeUnit.SECONDS)) {
                User reg = userMapper.selectByUserName(dto.getUserName());
                if (reg == null) {
                    LOGGER.info("zk-Lock,userName={}",dto.getUserName());
                    User user = new User();
                    BeanUtils.copyProperties(dto, user);
                    user.setCreateTime(new Date());
                    userMapper.insertSelective(user);
                } else {
                    throw new Exception("用户名已存在");
                }
            } else {
                throw new RuntimeException("获取锁失败");
            }
        } catch (Exception e){
            throw e;
        } finally {
            mutex.release();
        }
    }

    @Override
    public void userRegLockByRedisson(UserRegDto dto) throws Exception {
        final String key ="RedissonLock"+ dto.getUserName();
        //获取分布式锁实例
        RLock lock = redissonClient.getLock(key);
        try {
            //对共享资源上锁，上锁后10s自动释放
            lock.lock(10, TimeUnit.SECONDS);
            //业务处理逻辑
            User user = userMapper.selectByUserName(dto.getUserName());
            if (user != null) {
                LOGGER.info("redisson加锁，当前用户名：" + dto.getUserName());
                User entity = new User();
                BeanUtils.copyProperties(dto, entity);
                entity.setCreateTime(new Date());
                userMapper.insertSelective(entity);
            }
        } catch (Exception e) {
            throw new Exception("用户信息已存在");
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }
}
